package co.yixiang.yshop.server.controller;

import co.yixiang.yshop.module.pay.mq.producer.PayNoticeProducer;
import co.yixiang.yshop.module.pay.service.wechat.WechatV3VerifierService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * 默认 Controller，解决部分 module 未开启时的 404 提示。
 * 例如说，/bpm/** 路径，工作流
 * 
 * 同时包含支付回调通知接口（已移动到此处以确保能被正确扫描）
 *
 * @author yshop
 */
@Slf4j
@RestController
public class DefaultController {

    @Autowired(required = false)
    private WechatV3VerifierService wechatV3VerifierService;
    
    @Autowired(required = false)
    private ObjectMapper objectMapper;
    
    @Autowired(required = false)
    private PayNoticeProducer payNoticeProducer;
    
    @Autowired(required = false)
    private co.yixiang.yshop.module.pay.config.WechatPayProperties wechatPayProperties;

    private boolean isProd() {
        String active = System.getProperty("spring.profiles.active", System.getenv().getOrDefault("SPRING_PROFILES_ACTIVE", ""));
        return "prod".equalsIgnoreCase(active);
    }
    
    /**
     * 判断是否为 XML 格式
     */
    private boolean isXmlContent(String contentType, String body) {
        if (contentType != null && (contentType.contains("xml") || contentType.contains("XML"))) {
            return true;
        }
        // 兜底：尝试检测 body 开头是否是 XML
        if (body != null && body.trim().startsWith("<")) {
            return true;
        }
        return false;
    }
    
    /**
     * 验证微信支付 V2 签名（MD5）
     * 注意：生产环境必须配置 API 密钥
     */
    private boolean verifyWechatV2Sign(String requestBody) {
        try {
            // ✅ 从配置文件中获取微信支付 V2 的 API 密钥（mch-key）
            String apiKey = null;
            if (wechatPayProperties != null) {
                apiKey = wechatPayProperties.getMchKey();
                
                // 如果 mch-key 未配置或是占位符，尝试使用 api-v3-key（很多商户 V2 和 V3 密钥设置成一样的）
                if (apiKey == null || apiKey.isEmpty() || apiKey.contains("可选") || apiKey.contains("请填写")) {
                    apiKey = wechatPayProperties.getApiV3Key();
                    if (apiKey != null && !apiKey.isEmpty() && !apiKey.contains("请填写")) {
                        log.info("[WeChatPayNotify][V2] mch-key not configured, using api-v3-key (same key for V2 and V3)");
                    }
                }
            }
            
            // 兜底：尝试从环境变量获取
            if (apiKey == null || apiKey.isEmpty() || apiKey.contains("请填写")) {
                apiKey = System.getenv("WECHAT_V2_API_KEY");
            }
            
            if (apiKey == null || apiKey.isEmpty() || apiKey.contains("请填写")) {
                log.warn("[WeChatPayNotify][V2] API Key not configured, skip signature verification (DEV only)");
                // 开发环境可以暂时跳过验签，生产环境必须验签
                return !isProd();
            }
            
            // 提取签名
            String sign = extractXmlValue(requestBody, "sign");
            if (sign == null || sign.isEmpty()) {
                log.error("[WeChatPayNotify][V2] sign field is empty");
                return false;
            }
            
            // 提取所有字段构建签名字符串
            // 微信 V2 签名规则：按字段名 ASCII 排序，key=value&key=value 拼接，最后加上 &key=API密钥
            String signStr = buildV2SignString(requestBody, apiKey);
            String calculatedSign = md5(signStr).toUpperCase();
            
            boolean verified = calculatedSign.equals(sign);
            if (!verified) {
                log.error("[WeChatPayNotify][V2] signature verification failed, expected={}, actual={}", calculatedSign, sign);
            }
            return verified;
            
        } catch (Exception e) {
            log.error("[WeChatPayNotify][V2] signature verification exception", e);
            return false;
        }
    }
    
    /**
     * 构建微信 V2 签名字符串（完整版）
     * 提取所有字段（除 sign）并按字典序排序
     */
    private String buildV2SignString(String xml, String apiKey) {
        Map<String, String> params = new java.util.TreeMap<>();  // TreeMap 自动按 key 排序
        
        // 常见的微信支付 V2 字段
        String[] possibleFields = {
            "return_code", "return_msg", "result_code", "err_code", "err_code_des",
            "appid", "mch_id", "device_info", "nonce_str", "sign_type",
            "openid", "is_subscribe", "trade_type", "bank_type",
            "total_fee", "settlement_total_fee", "fee_type", "cash_fee", "cash_fee_type",
            "transaction_id", "out_trade_no", "attach", "time_end",
            "coupon_fee", "coupon_count", "coupon_type_0", "coupon_id_0", "coupon_fee_0"
        };
        
        // 提取所有存在的字段
        for (String field : possibleFields) {
            String value = extractXmlValue(xml, field);
            if (value != null && !value.isEmpty()) {
                params.put(field, value);
            }
        }
        
        // 按字典序拼接：key1=value1&key2=value2...
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (sb.length() > 0) sb.append("&");
            sb.append(entry.getKey()).append("=").append(entry.getValue());
        }
        
        // 最后加上密钥
        sb.append("&key=").append(apiKey);
        
        log.debug("[WeChatPayNotify][V2] Sign string: {}", sb.toString());
        return sb.toString();
    }
    
    /**
     * MD5 加密
     */
    private String md5(String str) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(str.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte b : array) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("[WeChatPayNotify][V2] MD5 failed", e);
            return "";
        }
    }
    
    /**
     * 解析 XML 格式的微信支付回调（V2 版本）
     */
    private String processXmlNotify(String requestBody) {
        try {
            // 简单的 XML 解析，提取 out_trade_no
            String outTradeNo = extractXmlValue(requestBody, "out_trade_no");
            String resultCode = extractXmlValue(requestBody, "result_code");
            String returnCode = extractXmlValue(requestBody, "return_code");
            
            log.info("[WeChatPayNotify][XML] return_code={}, result_code={}, out_trade_no={}", 
                    returnCode, resultCode, outTradeNo);
            
            // 必须先检查 return_code
            if (!"SUCCESS".equalsIgnoreCase(returnCode)) {
                log.error("[WeChatPayNotify][XML] return_code is not SUCCESS");
                return null;
            }
            
            if ("SUCCESS".equalsIgnoreCase(resultCode) && outTradeNo != null && !outTradeNo.isEmpty()) {
                if (payNoticeProducer != null) {
                    log.info("✅ [WeChatPayNotify][XML] 发送MQ消息：orderId={}, payType=weixin", outTradeNo);
                    payNoticeProducer.sendPayNoticeMessage(outTradeNo, "weixin");
                    log.info("✅ [WeChatPayNotify][XML] MQ消息发送成功");
                } else {
                    log.error("❌ [WeChatPayNotify][XML] PayNoticeProducer 未注入，无法发送MQ消息！");
                }
                return outTradeNo;
            } else {
                log.warn("⚠️ [WeChatPayNotify][XML] 不满足发送MQ条件：returnCode={}, resultCode={}, outTradeNo={}", 
                        returnCode, resultCode, outTradeNo);
            }
        } catch (Exception e) {
            log.error("[WeChatPayNotify][XML] parse exception", e);
        }
        return null;
    }
    
    /**
     * 简单的 XML 值提取（支持 CDATA 格式）
     */
    private String extractXmlValue(String xml, String tagName) {
        // ✅ 先尝试 CDATA 格式（避免把 CDATA 标签也提取出来）
        String cdataStartTag = "<" + tagName + "><![CDATA[";
        String cdataEndTag = "]]></" + tagName + ">";
        int cdataStart = xml.indexOf(cdataStartTag);
        int cdataEnd = xml.indexOf(cdataEndTag);
        if (cdataStart >= 0 && cdataEnd > cdataStart) {
            return xml.substring(cdataStart + cdataStartTag.length(), cdataEnd).trim();
        }
        
        // ✅ 再尝试普通格式
        String startTag = "<" + tagName + ">";
        String endTag = "</" + tagName + ">";
        int start = xml.indexOf(startTag);
        int end = xml.indexOf(endTag);
        if (start >= 0 && end > start) {
            String value = xml.substring(start + startTag.length(), end).trim();
            // 如果还包含 CDATA，去掉它
            if (value.startsWith("<![CDATA[") && value.endsWith("]]>")) {
                value = value.substring(9, value.length() - 3).trim();
            }
            return value;
        }
        
        return null;
    }

    // ==================== 订单支付回调 ====================
    
    @PermitAll
    @GetMapping({"/admin-api/pay/notify/order", "/app-api/pay/notify/order"})
    public ResponseEntity<Map<String, String>> getOrderNotifyPing() {
        // 生产环境限制已去除，方便测试接口可达性
        // if (isProd()) {
        //     return ResponseEntity.notFound().build();
        // }
        Map<String, String> body = new HashMap<>();
        body.put("code", "SUCCESS");
        body.put("message", "order notify endpoint is reachable. Use POST from WeChat Pay.");
        return ResponseEntity.ok(body);
    }

    @PermitAll
    @PostMapping(value = {"/admin-api/pay/notify/order", "/app-api/pay/notify/order"}, 
                 consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE })
    public ResponseEntity<?> orderNotify(HttpServletRequest request,
                                        @RequestBody(required = false) String requestBody,
                                        @RequestHeader Map<String, String> headers) {
        String contentType = request.getContentType();
        log.info("[WeChatPayNotify][order] contentType={}, headers={}, body={}", contentType, headers, requestBody);
        
        if (requestBody == null) requestBody = "";
        
        // 判断是否为 XML 格式（微信支付 V2）
        if (isXmlContent(contentType, requestBody)) {
            log.info("[WeChatPayNotify][order] detected XML format, using V2 processing");
            
            // ✅ 验证签名（生产环境必须）
            boolean signVerified = verifyWechatV2Sign(requestBody);
            if (!signVerified) {
                log.error("[WeChatPayNotify][order] V2 signature verification failed");
                String xmlFailResponse = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名验证失败]]></return_msg></xml>";
                return ResponseEntity.ok()
                        .contentType(MediaType.TEXT_XML)
                        .body(xmlFailResponse);
            }
            
            String orderNo = processXmlNotify(requestBody);
            log.info("[WeChatPayNotify][order] XML processed, orderNo={}", orderNo);
            
            if (orderNo != null) {
                log.info("✅ [WeChatPayNotify][order] MQ消息已发送，等待消费者更新订单状态...");
            } else {
                log.warn("⚠️ [WeChatPayNotify][order] 未发送MQ消息（订单号为空或状态不是SUCCESS）");
            }
            
            // 微信支付 V2 期望 XML 格式响应
            String xmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
            return ResponseEntity.ok()
                    .contentType(MediaType.TEXT_XML)
                    .body(xmlResponse);
        }
        
        // JSON 格式处理（微信支付 V3）
        // 检查必要的服务是否可用
        if (wechatV3VerifierService == null || objectMapper == null || payNoticeProducer == null) {
            log.error("[WeChatPayNotify][order] required services not available");
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "服务未就绪");
            return ResponseEntity.status(503).body(fail);
        }
        
        boolean ok = wechatV3VerifierService.verifySignature(headers, requestBody);
        if (!ok) {
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "签名校验失败");
            return ResponseEntity.badRequest().body(fail);
        }
        try {
            JsonNode root = objectMapper.readTree(requestBody);
            JsonNode resource = root.path("resource");
            if (!resource.isMissingNode()) {
                String associatedData = resource.path("associated_data").asText(null);
                String nonce = resource.path("nonce").asText("");
                String ciphertext = resource.path("ciphertext").asText("");
                String plainText = wechatV3VerifierService.decryptResource(associatedData, nonce, ciphertext);
                log.info("[WeChatPayNotify][order] decrypted={}", plainText);
                JsonNode plain = objectMapper.readTree(plainText);
                String tradeState = plain.path("trade_state").asText("");
                String outTradeNo = plain.path("out_trade_no").asText("");
                if ("SUCCESS".equalsIgnoreCase(tradeState) && outTradeNo != null && !outTradeNo.isEmpty()) {
                    // 通过 MQ 异步落单，幂等更新
                    log.info("✅ [WeChatPayNotify][order] 发送MQ消息：orderId={}, payType=weixin", outTradeNo);
                    payNoticeProducer.sendPayNoticeMessage(outTradeNo, "weixin");
                    log.info("✅ [WeChatPayNotify][order] MQ消息发送成功，等待消费者处理...");
                } else {
                    log.warn("⚠️ [WeChatPayNotify][order] 不满足发送MQ条件：tradeState={}, outTradeNo={}", tradeState, outTradeNo);
                }
            }
        } catch (Exception e) {
            log.error("[WeChatPayNotify][order] process exception", e);
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "处理异常");
            return ResponseEntity.badRequest().body(fail);
        }
        Map<String, String> resp = new HashMap<>();
        resp.put("code", "SUCCESS");
        resp.put("message", "成功");
        return ResponseEntity.ok(resp);
    }

    // ==================== 退款回调 ====================
    
    @PermitAll
    @GetMapping({"/admin-api/pay/notify/refund", "/app-api/pay/notify/refund"})
    public ResponseEntity<Map<String, String>> getRefundNotifyPing() {
        // 生产环境限制已去除，方便测试接口可达性
        // if (isProd()) {
        //     return ResponseEntity.notFound().build();
        // }
        Map<String, String> body = new HashMap<>();
        body.put("code", "SUCCESS");
        body.put("message", "refund notify endpoint is reachable. Use POST from WeChat Pay.");
        return ResponseEntity.ok(body);
    }

    @PermitAll
    @PostMapping(value = {"/admin-api/pay/notify/refund", "/app-api/pay/notify/refund"}, 
                 consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE })
    public ResponseEntity<?> refundNotify(HttpServletRequest request,
                                         @RequestBody(required = false) String requestBody,
                                         @RequestHeader Map<String, String> headers) {
        String contentType = request.getContentType();
        log.info("[WeChatPayNotify][refund] contentType={}, headers={}, body={}", contentType, headers, requestBody);
        
        if (requestBody == null) requestBody = "";
        
        // 判断是否为 XML 格式（微信支付 V2）
        if (isXmlContent(contentType, requestBody)) {
            log.info("[WeChatPayNotify][refund] detected XML format, using V2 processing");
            
            // ✅ 验证签名（生产环境必须）
            boolean signVerified = verifyWechatV2Sign(requestBody);
            if (!signVerified) {
                log.error("[WeChatPayNotify][refund] V2 signature verification failed");
                String xmlFailResponse = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名验证失败]]></return_msg></xml>";
                return ResponseEntity.ok()
                        .contentType(MediaType.TEXT_XML)
                        .body(xmlFailResponse);
            }
            
            // XML 格式退款通知处理（可扩展）
            String outRefundNo = extractXmlValue(requestBody, "out_refund_no");
            String refundStatus = extractXmlValue(requestBody, "refund_status");
            log.info("[WeChatPayNotify][refund] XML refund, out_refund_no={}, status={}", outRefundNo, refundStatus);
            
            // 微信支付 V2 期望 XML 格式响应
            String xmlResponse = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
            return ResponseEntity.ok()
                    .contentType(MediaType.TEXT_XML)
                    .body(xmlResponse);
        }
        
        // JSON 格式处理（微信支付 V3）
        // 检查必要的服务是否可用
        if (wechatV3VerifierService == null || objectMapper == null) {
            log.error("[WeChatPayNotify][refund] required services not available");
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "服务未就绪");
            return ResponseEntity.status(503).body(fail);
        }
        
        boolean ok = wechatV3VerifierService.verifySignature(headers, requestBody);
        if (!ok) {
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "签名校验失败");
            return ResponseEntity.badRequest().body(fail);
        }
        try {
            JsonNode root = objectMapper.readTree(requestBody);
            JsonNode resource = root.path("resource");
            if (!resource.isMissingNode()) {
                String associatedData = resource.path("associated_data").asText(null);
                String nonce = resource.path("nonce").asText("");
                String ciphertext = resource.path("ciphertext").asText("");
                String plainText = wechatV3VerifierService.decryptResource(associatedData, nonce, ciphertext);
                log.info("[WeChatPayNotify][refund] decrypted={}", plainText);
                // 可在此解析 out_trade_no / out_refund_no / refund_status，并做幂等更新
                // 暂时仅记录日志，订单退款状态更新可在后续实现或通过现有退款流程同步
            }
        } catch (Exception e) {
            log.error("[WeChatPayNotify][refund] process exception", e);
            Map<String, String> fail = new HashMap<>();
            fail.put("code", "FAIL");
            fail.put("message", "处理异常");
            return ResponseEntity.badRequest().body(fail);
        }
        Map<String, String> resp = new HashMap<>();
        resp.put("code", "SUCCESS");
        resp.put("message", "成功");
        return ResponseEntity.ok(resp);
    }

}
